package com.beta.cat.config.sms;

import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.security.cert.X509Certificate;
import java.util.Properties;

/**
 * 手机验证码发送及校验功能。使用方法：<br>
 * <ul>
 *     <li>在需要的应用/项目中，引用当前jar包</li>
 *     <li>在应用的properties文件中，配置com.beta.sms.verify.enable=true</li>
 *     <li>properties或配置中心增加第三方组件中需要配置的参数，以接入beta短信验证码为例，配置如下：
 * <pre>
 * com.beta.sms.verify.enable=true
 *
 * com.beta.sms.url.pre=/sms/code #可以指定url前缀,默认前缀是:/sms/code.具体操作上,发送是/send,验证是/verify.所以,默认完整的发送url就是:/sms/code/send
 *
 * com.beta.sms.verify.privateKey=e792cd88bc5bb65e024902128aa893f5beta
 * com.beta.sms.verify.secretKey=ncoSig\=REGISTER921a72755eca4ca1eef7dd3584ac96bc7819257e&ncoChallenge\=%d&ncoSessionid\=%s&ncoToken\=%s
 * com.beta.sms.verify.serverUrl=http://50.test.betawm.com
 * com.beta.sms.verify.settings.serverAesKey=!~zBw@$]1sms8#Wm
 * com.beta.sms.verify.settings.smsPath=/AuthServer/SMSManager.aspx?parms\=%s
 * com.beta.sms.verify.settings.sendParam=op\=SendValidCodeNew&fromid\=22&mbphone=%s&ip=%s&key=%s
 * com.beta.sms.verify.settings.verifyParam=op\=CheckValidCode&fromid\=22&mbphone=%s&code=%d&ip=%s&key=%s
 * </pre>
 *     </li>
 * </ul>
 */
@Configuration
@ConditionalOnProperty(name = "com.beta.sms.verify.enable", havingValue = "true", matchIfMissing = false)
public class SmsVerifyCodeAutoConfiguration {
    private final Logger log = LoggerFactory.getLogger(SmsVerifyCodeAutoConfiguration.class);

    @Component
    @ConfigurationProperties(prefix = "com.beta.sms.verify")
    @RefreshScope
    @Data
    public class SmsVerifyProperties {
        //密钥id
        private String privateKey;
        //密钥key
        private String secretKey;
        //服务器域名
        private String serverUrl;
        //使用哪个第三方的组件，默认使用beta的
        private String product = BetaSmsVerifyCodeService.PRODUCT_NAME;
        //其它，不同验证码组件的不同配置
        private Properties settings;

        public String getStrSetting(String key) {
            String val = settings.getProperty(key, "");
            return StringUtils.isBlank(val) ? null : val;
        }

        public Integer getIntSetting(String key) {
            String val = settings.getProperty(key, "");
            return StringUtils.isBlank(val) ? null : Integer.parseInt(val.trim());
        }

        public Long getLongSetting(String key) {
            String val = settings.getProperty(key, "");
            return StringUtils.isBlank(val) ? null : Long.parseLong(val.trim());
        }
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
    public SmsVerifyCodeController createSmsVerifyController() {
        return new SmsVerifyCodeController();
    }

    /**
     * 实现默认指定的内置服务。如果内置的不符合要求，可以自己在应用中实现接口中的方法，并加入到Springboot容器中即可。
     *
     * @param properties 配置信息
     * @return 具体的三方实现逻辑
     */
    @Bean
    @ConditionalOnMissingBean
    public SmsVerifyService createBetaSmsVerifyService(SmsVerifyProperties properties) {
        if (BetaSmsVerifyCodeService.PRODUCT_NAME.equalsIgnoreCase(properties.getProduct())) {
            return new BetaSmsVerifyCodeService();
        } else {
            throw new IllegalArgumentException("com.beta.sms.verify.product配置的内容不合法，没有对应的实现类");
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public RestTemplate restHttpsTemplate() throws Exception {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
        SSLContext sslContext = SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
    }

}
